#pragma once

#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include <sstream>
#include <ctime>
#include <cassert>
#include <vector>

namespace iceLogs
{
    //抽象格式化子项基类
    class FormatItem
    {
        public:
            using ptr = std::shared_ptr<FormatItem>;
            virtual void format(std::ostream &out, logMsg &_msg) = 0;
    };
    //派生格式化子项子类--消息、等级、时间、文件名、行号、线程ID、日志器名称、制表符、换行、其他

    class MsgFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _msg._payload;
            }
    };
    class LevelFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << logLevel::toString(_msg._level);
            }
    };
    class TimeFormatItem : public FormatItem
    {
        public:
            TimeFormatItem(const std::string& fmt):_fmt_time(fmt)
            {

            }
            void format(std::ostream &out, logMsg &_msg)
            {
                struct tm t;
                localtime_r(&_msg._ctime, &t);//把时间戳按照一定格式转换到tm类型的结构体对象中
                char tmp[32] = {0};
                strftime(tmp, 31, _fmt_time.c_str(), &t);//把tm类型的结构体对象按照自定义的格式保存到字符数组中
                out << tmp;
            }
        private:
            std::string _fmt_time;
    };
    class FileFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _msg._file;
            }
    };
    class LineFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _msg._line;
            }
    };
    class ThreadFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _msg._tid;
            }
    };
    class LoggerFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _msg._logger;
            }
    };
    class TabFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << '\t';
            }
    };
    class NlineFormatItem : public FormatItem
    {
        public:
            void format(std::ostream &out, logMsg &_msg)
            {
                out << '\n';
            }
    };
    class OtherFormatItem : public FormatItem
    {
        public:
            OtherFormatItem(const std::string& str):_str(str){}
            void format(std::ostream &out, logMsg &_msg)
            {
                out << _str;
            }
        private:
            std::string _str;

    };

    /*
        %d  表示日期，包含子格式{%H:%M:%S}
        %t  表示线程ID
        %c  表示日志器名称
        %f  表示源码文件名
        %l  表示源码文件行号
        %p  表示日志等级
        %T  表示制表符缩进
        %m  表示消息主体
        %n  表示换行
    */

    class Formatter
    {
        public:
            using ptr = std::shared_ptr<Formatter>;
            Formatter(const std::string& pattern = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
            :_pattern(pattern)
            {
                assert(parsePattern());
            }
            //对msg消息进行格式化
            void format(std::ostream& out, logMsg& msg)
            {
                for(auto& e : _items)
                {
                    e->format(out, msg);
                }
            }
            std::string format(logMsg& msg)
            {
                std::stringstream ss;
                format(ss, msg);
                return ss.str();
            }
        private:
            //对格式化规则字符串进行解析
            bool parsePattern()
            {
                //1.对格式化规则字符串进行解析
                std::vector<std::pair<std::string, std::string>> fmt_order;
                size_t pos = 0;
                std::string key, val;
                while(pos < _pattern.size())
                {
                    if(_pattern[pos] != '%')
                    {
                        val.push_back(_pattern[pos++]);
                        continue;
                    }
                    //走到这说明是% 处理%%问题
                    if(_pattern[pos+1] == '%' && pos + 1 < _pattern.size())
                    {
                        val.push_back('%');
                        pos+=2;
                        continue;
                    }

                    //走到这说明原始字符串处理完毕
                    if (val.empty() == false)
                    {
                        fmt_order.push_back(make_pair("", val));
                        val.clear();
                    }

                    pos+=1;
                    if(pos == _pattern.size())
                    {
                        std::cout << "%后没有格式化字符！" << std::endl;
                        return false;
                    }
                    key = _pattern[pos];
                    pos+=1;
                    //此时pos指向格式化字符后面的位置
                    if(_pattern[pos] == '{' && pos < _pattern.size())
                    {
                        pos+=1;//这时候pos指向子格式起始位置
                        while(_pattern[pos] != '}' && pos < _pattern.size())
                        {
                            val.push_back(_pattern[pos]);
                            pos++;
                        }
                        //跳出循环两种可能1.走到结尾没有找到} 2.找到了}
                        if(pos == _pattern.size())
                        {
                            std::cout << "子规则{}匹配失败！" << std::endl;
                            return false;
                        }
                        pos++;//走到下次处理的位置
                    }

                    fmt_order.push_back(std::make_pair(key, val));
                    key.clear();
                    val.clear();
                }
                
                for(auto& it : fmt_order)
                {
                    _items.push_back(createItem(it.first, it.second));
                }
                return true;

            }
        
            //根据不同的格式化字符创建不同的格式化子项对象 
            FormatItem::ptr createItem(const std::string& key, const std::string& val)
            {
            /*
                %d  表示日期，包含子格式{%H:%M:%S}
                %t  表示线程ID
                %c  表示日志器名称
                %f  表示源码文件名
                %l  表示源码文件行号
                %p  表示日志等级
                %T  表示制表符缩进
                %m  表示消息主体
                %n  表示换行
            */
                if(key == "d") return std::make_shared<TimeFormatItem>(val);
                if(key == "t") return std::make_shared<ThreadFormatItem>();
                if(key == "c") return std::make_shared<LoggerFormatItem>();
                if(key == "f") return std::make_shared<FileFormatItem>();
                if(key == "l") return std::make_shared<LineFormatItem>();
                if(key == "p") return std::make_shared<LevelFormatItem>();
                if(key == "T") return std::make_shared<TabFormatItem>();
                if(key == "m") return std::make_shared<MsgFormatItem>();
                if(key == "n") return std::make_shared<NlineFormatItem>();

                if(key == "") return std::make_shared<OtherFormatItem>(val);

                std::cout << "没有匹配的格式化字符！" << std::endl;

                abort();

                return FormatItem::ptr();

            }


        private:
            std::string _pattern;   //格式化字符规则
            std::vector<FormatItem::ptr> _items;

    };
    
}